package com.summerbird.mallchat.common.common.utils.sensitiveWord;

import com.summerbird.mallchat.common.sensitive.MyWordFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;

public final class DFAFilter implements SensitiveWordFilter {

    private DFAFilter() {
    }

    private static Word root = new Word(' '); // 敏感词字典的根节点
    private final static char replace = '*'; // 替代字符
    private final static String skipChars = " !*-+_=,，.@;:；：。、？?（）()【】[]《》<>“”\"‘’"; // 遇到这些字符就会跳过
    private final static Set<Character> skipSet = new HashSet<>(); // 遇到这些字符就会跳过

    // 加载无意义字符
    static {
        for(char c : skipChars.toCharArray()){
            skipSet.add(c);
        }
    }

    public static DFAFilter getInstance() {
        return new DFAFilter();
    }

    /**
     * 判断文本中是否存在敏感词
     *
     * @param text 文本
     * @return true: 存在敏感词, false: 不存在敏感词
     */
    @Override
    public boolean hasSensitiveWord(String text) {
        return !Objects.equals(filter(text), text);
    }

    /**
     * 敏感词替换
     * @param text 文本
     * @return
     */
    @Override
    public String filter(String text) {
        StringBuilder result = new StringBuilder(text);
        int index = 0;
        while (index < result.length()){
            char c = result.charAt(index);
            if(skip(c)){
                index++;
                continue;
            }
            Word word = root;
            boolean found = false;
            int start = index;
            for(int i = start; i < result.length(); ++i){
                c = result.charAt(i);
                if(skip(c)){
                    continue;
                }
                if(c >= 'A' && c <= 'Z'){
                    c += 32;
                }
                word = word.next.get(c);
                if(word == null){
                    break;
                }
                if(word.end){
                    found = true;
                    for(int j = start; j <= i; ++j){
                        result.setCharAt(j, replace);
                    }
                    index = i + 1;
                }
            }

            if(!found){
                index++;
            }
        }
        return result.toString();
    }

    /**
     * 加载敏感词列表
     * @param words 敏感词数组
     */
    @Override
    public void loadWord(List<String> words) {
        if(!CollectionUtils.isEmpty(words)){
            Word newRoot = new Word(' ');
            words.forEach(word -> loadWord(word, newRoot));
            root = newRoot;
        }
    }

    /**
     * 加载敏感词
     * @param word
     * @param root
     */
    private void loadWord(String word, Word root) {
        if(StringUtils.isBlank(word)){
            return;
        }
        char[] wordCharArray = word.toCharArray();
        Word current = root;
        for(char c : wordCharArray){
            // 如果是大写字母，则转换成小写
            if(c >= 'A' && c <= 'Z'){
                c += 32;
            }
            if(skip(c)){
                continue;
            }
            Word next = current.next.get(c);
            if(next == null){
                next = new Word(c);
                current.next.put(c, next);
            }
            current = next;
        }
        current.end = true;
    }

    /**
     * 判断是否需要跳过当前字符
     *
     * @param c 待检测字符
     * @return true: 需要跳过, false: 不需要跳过
     */
    private boolean skip(char c) {
        return skipSet.contains(c);
    }

    /**
     * 敏感词类
     */
    private static class Word {
        // 当前字符
        private final char c;

        // 结束标识
        private boolean end;

        // 下一层级的敏感词字典
        private Map<Character, Word> next;

        public Word(char c) {
            this.c = c;
            this.next = new HashMap<>();
        }
    }
}
